package cn.iocoder.yudao.module.system.service.area;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.controller.admin.area.vo.AreaPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.area.vo.AreaSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.area.AreaDO;
import cn.iocoder.yudao.module.system.dal.mysql.area.AreaMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.AREA_NOT_EXISTS;

/**
 * 地区 Service 实现类
 *
 * @author 吕小文
 */
@Service
@Validated
@Slf4j
public class AreaServiceImpl implements AreaService {

    @Getter
    private volatile Map<String, List<AreaDO>> areaCache;

    @Getter
    private volatile Map<String,AreaDO> provinceCache;

    @Getter
    private volatile Map<String,AreaDO> cityCache;

    @Resource
    private AreaMapper areaMapper;

    @PostConstruct
    private void init(){
        long now = System.currentTimeMillis();
        areaCache = new HashMap<>();
        List<AreaDO> list = areaMapper.selectList(new LambdaQueryWrapper<AreaDO>().ne(AreaDO::getName,"苏鲁交界"));
        log.info("[initLocalArea][缓存地区，数据{}]",list.size());
        if (!CollectionUtils.isEmpty(list)) {
            areaCache = convertMultiMap(list, AreaDO::getPid);

            provinceCache = list.stream().filter(item -> 1 == item.getLevel()).collect(Collectors.toMap(AreaDO::getId, Function.identity(), (v1, v2) -> v1));
            cityCache = list.stream().filter(item -> 2 == item.getLevel()).collect(Collectors.toMap(AreaDO::getId, Function.identity(), (v1, v2) -> v1));
        }
        log.info("启动加载 地区 成功，耗时 ({}) 毫秒", System.currentTimeMillis() - now);
    }

    //基于缓存获取地区数据
    @Override
    public List<AreaDO> getAreaList(String pid) {
        List<AreaDO> list = new ArrayList<>();
        if (!CollectionUtils.isEmpty(areaCache)){
            list = areaCache.get(pid);
        }
        if (CollectionUtils.isEmpty(list)){
            LambdaQueryWrapper<AreaDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(StringUtils.isNotBlank(pid),AreaDO::getPid,pid);
            List<AreaDO> dbList = areaMapper.selectList(lambdaQueryWrapper);
            log.info("mysql get area:pid:{},list:{}",pid,dbList.size());
            return dbList;
        }else{
//            log.info("cache get area:pid:{},list:{}",pid,list.size());
            return list;
        }
    }

    @Override
    public String createArea(AreaSaveReqVO createReqVO) {
        // 插入
        AreaDO area = BeanUtils.toBean(createReqVO, AreaDO.class);
        areaMapper.insert(area);
        // 返回
        return area.getId();
    }

    @Override
    public void updateArea(AreaSaveReqVO updateReqVO) {
        // 校验存在
        validateAreaExists(updateReqVO.getId());
        // 更新
        AreaDO updateObj = BeanUtils.toBean(updateReqVO, AreaDO.class);
        areaMapper.updateById(updateObj);
    }

    @Override
    public void deleteArea(String id) {
        // 校验存在
        validateAreaExists(id);
        // 删除
        areaMapper.deleteById(id);
    }

    private void validateAreaExists(String id) {
        if (areaMapper.selectById(id) == null) {
            throw exception(AREA_NOT_EXISTS);
        }
    }

    @Override
    public AreaDO getArea(String id) {
        return areaMapper.selectById(id);
    }

    @Override
    public PageResult<AreaDO> getAreaPage(AreaPageReqVO pageReqVO) {
        return areaMapper.selectPage(pageReqVO);
    }

    @Override
    public void refreshArea() {
        init();
    }

}